package com.sunye.redis;

import org.redisson.Redisson;
import org.redisson.api.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.ValueOperations;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.UUID;
import java.util.concurrent.TimeUnit;

@RequestMapping("redisController")
@RestController
public class RedisController {
    @Autowired
    private Redisson redisson;

    @Autowired
    private RedissonClient redissonClient;

    @Autowired
    private RedisTemplate redisTemplate;


    //redis实现分布式锁
    @RequestMapping("/distributedLock")
    public String distributedLock(){
        String key = "k1";
        ValueOperations valueOperations = redisTemplate.opsForValue();
        String uuid = UUID.randomUUID().toString();
        try {
            Boolean isLock = valueOperations.setIfAbsent(key, uuid,5, TimeUnit.SECONDS);//设置锁的过期时间避免死锁
            if (isLock) {
                //如果没有锁
                System.out.println("处理业务中....");
                Thread.sleep(1000);//模拟处理业务
                return "处理业务成功";
            }else{
                //如果有锁  正常处理结构应该是让该线程等待
                return "当前访问人数过多";
            }
        }catch (Exception e){
            e.printStackTrace();
        }finally {
            String value = (String)redisTemplate.opsForValue().get(key);
            System.out.println("value = " + value);
            if (uuid.equals(value)) {
                redisTemplate.delete(key);
            }
        }
        return "请求成功";

    }

    //redission实现分布式锁  阻塞
    @RequestMapping("/distributedLock2")
    public String distributedLock2() {
        String key = "k2";
        //获取分布式锁
        RLock lock = redisson.getLock(key);
        // 加锁（阻塞等待），默认过期时间是30s
        lock.lock(30,TimeUnit.SECONDS);
        try {
            System.out.println("处理业务中....");
            Thread.sleep(1000);//模拟处理业务
        }catch (Exception e){
            e.printStackTrace();
        }finally {
            lock.unlock();
        }
        return "请求成功";
    }

    //redission实现分布式锁  非阻塞   ****常用*******
    @RequestMapping("/distributedLock3")
    public String distributedLock3() {
        String key = "k3";
        //获取分布式锁
        RLock lock = redisson.getLock(key);
        try {
            if(lock.tryLock(2,10,TimeUnit.SECONDS)){//最多等待锁2秒  10秒后强制解锁防止死锁
                System.out.println("处理业务中....");
                Thread.sleep(3000);//模拟处理业务
            }else{
                System.out.println("已经抢光....");
            }
        }catch (Exception e){
            e.printStackTrace();
        }finally {
            lock.unlock();
        }
        return "请求成功";
    }

    //for update 实现分布式锁
    @PostMapping("mysqlLock")
    @Transactional(rollbackFor = Exception.class)
    public String testLock(String id) throws Exception {
        try {
//            List<Map<String, Object>> list = communityCompanyService.getList(id);
            List<Map<String, Object>> list = new ArrayList<>();
            if(list.size()>0){
                System.out.println("获取到分布式锁");
                String isPoint = list.get(0).get("is_point") == null ? "1" : list.get(0).get("is_point").toString();
                if("1".equals(isPoint)){
                    System.out.println("重点不能提交释放分布式锁");
                    throw new Exception("重点不能提交释放分布式锁");
                }
                Thread.sleep(30 * 1000);//处理业务
            }else{
                System.out.println("获取分布式锁失败");
                throw new Exception("获取分布式锁失败；");
            }
        }catch (Exception e){
            System.out.println("获取分布式锁失败");
//            throw new Exception("获取分布式锁失败；");
        }
        return "返回结果";
    }

    //初始化（创建）限流器
    @RequestMapping("/initRateLimit")
    public void initRateLimit(){
        // 1、 声明一个限流器
        RRateLimiter rateLimiter = redissonClient.getRateLimiter("rateLimiter");
        // 2、 设置速率，5秒中产生3个令牌
        rateLimiter.trySetRate(RateType.OVERALL, 3, 5, RateIntervalUnit.SECONDS);
    }
    //获取令牌
    @RequestMapping("/getRateLimit")
    public void getRateLimit(){
        // 1、 声明一个限流器
        RRateLimiter rateLimiter = redissonClient.getRateLimiter("rateLimiter");
        // 2、 试图获取一个令牌，获取到返回true
        if(rateLimiter.tryAcquire()){
            System.out.println("成功获取到令牌");
        }else{
            System.out.println("未获取到令牌");
        }
    }


    //简单接口限流  5秒内访问5次
    @RequestMapping("/interfaceLimit")
    public String interfaceLimit(String userId){
        if(userId ==null){
            return "userId不能为空";
        }
        ValueOperations redis = redisTemplate.opsForValue();
        Integer interfaceLimit = ((Integer) redis.get("interfaceLimit:" + userId));
        if(interfaceLimit ==null){
            redis.set("interfaceLimit:"+userId,1,5,TimeUnit.SECONDS);
            return "第一次请求成功";
        }else{
            System.out.println("interfaceLimit = " + interfaceLimit);
            if(interfaceLimit>5){
                return "请求被限制";
            }else{
                redis.increment("interfaceLimit:" + userId);
                return "请求成功";
            }
        }

    }






}
